﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using GameEngine.SceneGraph;

namespace Redland2
{
    public class Player : Entity
    {
        #region members
        
        private const Keys MOVE_UP_BUTTON = Keys.W;
        private const Keys MOVE_DOWN_BUTTON = Keys.S;
        private const Keys MOVE_LEFT_BUTTON = Keys.A;
        private const Keys MOVE_RIGHT_BUTTON = Keys.D;
        private const float PLAYER_MOVE_SPEED = 3.0F;
        private const int PLAYER_IDLE_FRAME = 4;

        private int speedMod = 0;

        private int _health;
        private int _keyspressed;
        private Vector2 _target;
        private bool _playerOne;
        private Gun _gun;
        private Axe _axe;
        private List<Powerup> _powerups;

        #endregion members

        #region properties
        public void ZeroVelocity()
        {
            this.XVelocity = 0.0F;
            this.YVelocity = 0.0F;
        }

        public int Health
        {
            get { return _health; }
            set { _health = value; if (_health > 100) _health = 100; }
        }

        public int Speed
        {
            get { return speedMod; }
            set { speedMod = value; }
        }

        public Gun Gun
        {
            get { return _gun; }
            set { _gun = value; }
        }

        public Vector2 TargetPos
        {
            get { return _target; }
            set { _target = value; }
        }
        #endregion properties
        
        #region constructors

        public Player(GameScene inputScene, int inputIndex, bool PlayerOne ) : base(inputScene, inputIndex, GameScene.Current.Content.Load<Texture2D>("player"), new Vector2(640, 350))
        {
            _playerOne = PlayerOne;
            this.type = "player";
            SetupPlayer();
            if(PlayerOne)

                BindControls();
            _health = 100;
        }

        private void BindControls()
        {
            
            Scene.Current.Input.GetKey(MOVE_UP_BUTTON).ButtonPushed += startWalking;
            Scene.Current.Input.GetKey(MOVE_UP_BUTTON).ButtonDown += moveUp;
            Scene.Current.Input.GetKey(MOVE_UP_BUTTON).ButtonReleased += stopWalking;

            Scene.Current.Input.GetKey(MOVE_DOWN_BUTTON).ButtonPushed += startWalking;
            Scene.Current.Input.GetKey(MOVE_DOWN_BUTTON).ButtonDown += moveDown;
            Scene.Current.Input.GetKey(MOVE_DOWN_BUTTON).ButtonReleased += stopWalking;

            Scene.Current.Input.GetKey(MOVE_LEFT_BUTTON).ButtonPushed += startWalking;
            Scene.Current.Input.GetKey(MOVE_LEFT_BUTTON).ButtonDown += moveLeft;
            Scene.Current.Input.GetKey(MOVE_LEFT_BUTTON).ButtonReleased += stopWalking;

            Scene.Current.Input.GetKey(MOVE_RIGHT_BUTTON).ButtonPushed += startWalking;
            Scene.Current.Input.GetKey(MOVE_RIGHT_BUTTON).ButtonDown += moveRight;
            Scene.Current.Input.GetKey(MOVE_RIGHT_BUTTON).ButtonReleased += stopWalking;

            Scene.Current.Input.GetMouseButton(GameEngine.Input.MouseButton.Left).ButtonDown += Fire;
            Scene.Current.Input.GetMouseButton(GameEngine.Input.MouseButton.Right).ButtonDown += _axe.Fire;

            Scene.Current.Input.GetKey(Keys.D1).ButtonPushed += SwitchWeapon1;
            Scene.Current.Input.GetKey(Keys.D2).ButtonPushed += SwitchWeapon2;
            Scene.Current.Input.GetKey(Keys.D3).ButtonPushed += SwitchWeapon3;
            Scene.Current.Input.GetKey(Keys.D0).ButtonPushed += SwitchWeapon0;


        }

        private void SetupPlayer()
        {
            this.Layer = 0.9F;
            this.AnimationData.RowsColumns = new Vector2(4, 4);
            this.AnimationData.BeginEndFrames = new Vector2(0, 15);
            this.AnimationData.Frame = 4;
            this.AnimationData.AnimationSpeed = 0.035f;
            this.SetOffset(GameEngine.Drawables.Anchor.Center);

            this._keyspressed = 0;
            this._target = Vector2.Zero;
            this._powerups = new List<Powerup>(5);
            if( _playerOne) SetupGun();
        }

        private void SetupGun()
        {
            this._gun = new Rifle(scene, this.scene._entities.Count, this, this.Position);
            this._axe = new Axe(scene, this.scene._entities.Count, this, this.Position);
        }

        #endregion constructors

        #region methods

        public override void Update(GameTime gameTime)
        {
            if (_playerOne)
                _target = Scene.Current.Input.GetMousePosition();

            RotatePlayerToFacePoint(_target);

           for (int i = 0; i < _powerups.Count; i++)
            {
                _powerups.ElementAt(i).HeldEffect(gameTime);
                if (!_powerups.ElementAt(i).IsAlive())
                {
                    Powerup temp = _powerups.ElementAt(i);
                    _powerups.Remove(temp);
                }
            }
            if (this._health < 0) this.Kill();
            base.Update(gameTime);
            ZeroVelocity();
        }

        public void RotatePlayerToFacePoint(Vector2 Target)
        {
            Vector2 direction = this.Position - Target;
            direction.Normalize();
            this.Angle = (float)Math.Atan2(direction.Y, direction.X) - MathHelper.PiOver2;
        }

        #region NSEW Movement

        public void moveUp()
        {
            this.YVelocity -= (PLAYER_MOVE_SPEED + speedMod);
        }
        public void moveDown()
        {
            this.YVelocity += (PLAYER_MOVE_SPEED + speedMod);
        }
        public void moveLeft()
        {
            this.XVelocity -= (PLAYER_MOVE_SPEED + speedMod);
        }
        public void moveRight()
        {
            this.XVelocity += ( PLAYER_MOVE_SPEED + speedMod);
        }

        #endregion NSEW Movement

        #region Target Based Movement

        public void moveForward()
        {
            Vector2 direction = this.Position - _target;
            if (direction.Length() < 30)
                return;
            direction.Normalize();
            direction *= PLAYER_MOVE_SPEED + speedMod;

            this.XVelocity += -direction.X;
            this.YVelocity += -direction.Y;
        }
        public void moveBackward()
        {
            Vector2 direction = this.Position - _target;
            direction.Normalize();
            direction *= PLAYER_MOVE_SPEED + speedMod;

            this.XVelocity += direction.X;
            this.YVelocity += direction.Y;
        }
        public void strafeLeft()
        {
            Vector2 direction = this.Position - _target;
            direction.Normalize();
            direction = Vector2.Transform(direction, Matrix.CreateRotationZ(-MathHelper.PiOver2));

            direction *= PLAYER_MOVE_SPEED + speedMod;
            this.XVelocity += -direction.X;
            this.YVelocity += -direction.Y;
        }
        public void strafeRight()
        {
            Vector2 direction = this.Position - _target;
            direction.Normalize();
            direction = Vector2.Transform(direction, Matrix.CreateRotationZ(-MathHelper.Pi + MathHelper.PiOver2));

            direction *= PLAYER_MOVE_SPEED + speedMod;
            this.XVelocity += direction.X;
            this.YVelocity += direction.Y;
        }

        #endregion Target Based Movement

        public virtual void startWalking()
        {
            _keyspressed++;
            this.AnimationData.Animated = true;
        }
        public virtual void stopWalking(int duration)
        {
            _keyspressed--;
            if (_keyspressed == 0)
            {
                this.AnimationData.Animated = false;
                this.AnimationData.Frame = PLAYER_IDLE_FRAME;
            }
        }

        public override void HandleCollision()
        {
            foreach (Entity entity in _collisions)
            {
                if (entity.type == "bullet")
                {
                    Bullet bullet = (Bullet)entity;
                    if (entity.Owner == this) continue;  //to keep from running in to my own bullets
                    this._health -= bullet.Damage; 
                }

                if ( entity.type == "swing")
                {
                    MeleeSwing swing = (MeleeSwing)entity;
                    if (entity.Owner == this) continue;  //to keep from running in to my own melee 
                    this._health -= swing.Damage;
                }
                
                if (entity.type == "gun") continue; // don't hit guns..

                if (entity.type == "powerup") PickupPowerup(entity);

                if (entity.type == "lava") continue;


                                                                //First Attempt - works, but math heavy but sticks on wall joints.
               /* Vector2 dist = Position - entity.Position;
                double radian = Math.Atan2(dist.Y, dist.X);
                if (radian < 0) radian += MathHelper.TwoPi;
                double angle = MathHelper.ToDegrees((float)radian);

                if (angle > 135 && angle < 225)
                {
                    if (this.XVelocity > 0) this.XVelocity = 0;
                }
                if (angle < 135 && angle > 45)
                {
                    if (this.YVelocity < 0) this.YVelocity = 0;
                }
                if (angle < 315 && angle > 225)
                {
                    if (this.YVelocity > 0) this.YVelocity = 0;
                }
                if (angle > 315 || (angle > 0 && angle < 45))
                {
                    if (this.XVelocity < 0) this.XVelocity = 0;
                } */

                                                                    //Seccond Attempt - less math, but buggier
                /*
                if (this.XVelocity > 0 && (this.BoundingBox.Top < entity.BoundingBox.Bottom || this.BoundingBox.Bottom > entity.BoundingBox.Top))  
                {           // moving to the right and top is beyond bottom or bottom is beyond top
                    this.Position += new Vector2(entity.BoundingBox.Left - this.BoundingBox.Right -2, 0);
                }

                if (this.XVelocity < 0 && (this.BoundingBox.Top < entity.BoundingBox.Bottom || this.BoundingBox.Bottom > entity.BoundingBox.Top)) 
                {           // moving to the Left and top is beyond bottom or bottom is beyond top
                    this.Position += new Vector2(entity.BoundingBox.Right - this.BoundingBox.Left +2, 0);
                }

                if (this.YVelocity > 0 && (this.BoundingBox.Right > entity.BoundingBox.Left || this.BoundingBox.Left < entity.BoundingBox.Right)) 
                {           // moving down and Left is beyond Right or Right is beyond Left
                    this.Position += new Vector2(0, entity.BoundingBox.Top - this.BoundingBox.Bottom -2);
                }

                if (this.YVelocity < 0 && (this.BoundingBox.Right > entity.BoundingBox.Left || this.BoundingBox.Left < entity.BoundingBox.Right)) 
                {           // moving up Left is beyond Right or Right is beyond Left
                    this.Position += new Vector2(0,entity.BoundingBox.Bottom - this.BoundingBox.Top +2);
                }   */

                //Third attempt - simplest, bad jidder, but works the best 
                
                this.Position -= this.Velocity;

                

                if (this.Velocity == Vector2.Zero)
                {
                    Vector2 direction = entity.Position - this.Position;
                    direction.Normalize();
                    this.Position -= (direction);
                }

                
            }
            base.HandleCollision();
        }

        public void PickupPowerup(Entity entity)
        {
            Powerup temp = (Powerup) entity;
            _powerups.Add(temp.Pickup(this));
        }

        public void RemovePowerup(Powerup powerup)
        {
            powerup.Kill();
        }


        public override void Kill()
        {
            if(_gun != null) _gun.Kill();
            base.Kill();
        }

        public virtual void Fire()
        {
            if (_gun != null)
                _gun.Fire();
        }

        public virtual void SwitchWeapon(int weapon)
        {
            Gun temp = _gun;
            temp.Kill();
            switch (weapon)
            {
                case 1:
                    _gun = new Pistol(scene, scene._entities.Count, this, this.Position);
                    scene._entities.Add(_gun);
                    break;
                case 2:
                    _gun = new Shotgun(scene, scene._entities.Count, this, this.Position);
                    scene._entities.Add(_gun);
                    break;
                case 3:
                    _gun = new Rifle(scene, scene._entities.Count, this, this.Position);
                    scene._entities.Add(_gun);
                    break;
                case 0:
                    _gun = new Gun(scene, scene._entities.Count, this, this.Position);
                    scene._entities.Add(_gun);
                    break;
                default:
                    _gun = new Pistol(scene, scene._entities.Count, this, this.Position);
                    scene._entities.Add(_gun);
                    break;
            }

        }

        public virtual void SwitchWeapon1()
        {
            SwitchWeapon(1);
        }
        public virtual void SwitchWeapon2()
        {
            SwitchWeapon(2);
        }
        public virtual void SwitchWeapon3()
        {
            SwitchWeapon(3);
        }
        public virtual void SwitchWeapon0()
        {
            SwitchWeapon(0);
        }
        

        #endregion methods
    }
}
